﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using EDB.SmoothStreaming.Models;
using EDB.SmoothStreaming.Services;
using Microsoft.Expression.Encoder;
using Microsoft.Expression.Encoder.Profiles;

namespace EDB.SmoothStreaming.Encoder {
    public class Encoder : IEncoder {
        public bool Encode(string sourcePath, string destinationPath, VideoPart part) {
            bool result = false;
            Job job = null;
            string fileName = "ss";

            try {
                job = new Job();
                job.CreateSubfolder = false;
                job.DefaultMediaOutputFileName = fileName + ".{DefaultExtension}";
                job.OutputDirectory = destinationPath;

                MediaItem mediaItem = new MediaItem(sourcePath);
                mediaItem.VideoResizeMode = VideoResizeMode.Letterbox;
                mediaItem.OutputFormat = new MP4OutputFormat();

                MainH264VideoProfile videoProfile = new MainH264VideoProfile();
                videoProfile.BFrameCount = 1;
                videoProfile.EntropyMode = EntropyMode.Cavlc;
                //videoProfile.RDOptimizationMode = RDOptimizationMode.Off;
                //videoProfile.RDOptimization = false;
                videoProfile.KeyFrameDistance = new TimeSpan(0, 0, 2);
                videoProfile.InLoopFilter = false;
                videoProfile.MEPartitionLevel = MEPartitionLevel.EightByEight;
                //videoProfile.ReferenceFrames = 1;
                //videoProfile.NumberOfReferenceFrames = 1;
                videoProfile.SearchRange = 32;
                videoProfile.AutoFit = true;
                videoProfile.Force16Pixels = false;
                videoProfile.FrameRate = 0;
                videoProfile.SeparateFilesPerStream = true;
                videoProfile.SmoothStreaming = true;
                videoProfile.NumberOfEncoderThreads = 0;

                videoProfile.Streams.Clear();
                List<StreamInfo> streams = ParseStreamInfoString(part.VideoStreams);
                foreach (StreamInfo streamInfo in streams) {
                    videoProfile.Streams.Add(streamInfo);
                }

                mediaItem.OutputFormat.VideoProfile = videoProfile;

                ConstantBitrate audioBitrate = new ConstantBitrate(128, false, TimeSpan.Zero);
                AacAudioProfile audioProfile = new AacAudioProfile();
                audioProfile.Bitrate = audioBitrate;
                audioProfile.BitsPerSample = 16;
                audioProfile.Channels = 2;
                audioProfile.SamplesPerSecond = 44100;
                mediaItem.OutputFormat.AudioProfile = audioProfile;

                job.MediaItems.Add(mediaItem);
                job.Encode();

                if (part.ThumbnailCount > 0) {
                    int movieLength = Convert.ToInt32(job.MediaItems[0].FileDuration.TotalMilliseconds);
                    int markersInterval = movieLength / (part.ThumbnailCount + 2);
                    int markersCount = part.ThumbnailCount;

                    for (int i = 1; i <= markersCount; i++) {
                        Image bitmap = job.MediaItems[0].MainMediaFile.GetThumbnail(new TimeSpan(0, 0, 0, 0, markersInterval * i), job.MediaItems[0].DisplayVideoSize);
                        bitmap = bitmap.GetThumbnailImage(part.ThumbnailWidth, part.ThumbnailHeight, null, IntPtr.Zero);

                        ImageFormat imageFormat = ImageFormat.Jpeg;
                        switch (part.ThumbnailFormat) {
                            case ThumbnailFormat.Png:
                                imageFormat = ImageFormat.Png;
                                break;
                            case ThumbnailFormat.Gif:
                                imageFormat = ImageFormat.Gif;
                                break;
                        }

                        bitmap.Save(Path.Combine(destinationPath, String.Format("{0}-{1}.{2}", fileName, i, part.ThumbnailFormat.ToString().ToLower())), imageFormat);
                        bitmap.Dispose();
                    }
                }

                part.Duration = mediaItem.FileDuration.Ticks;

                result = true;
            }
            finally {
                if (job != null)
                    job.Dispose();
            }

            return result;
        }

        private List<StreamInfo> ParseStreamInfoString(string streamInfoString) {
            List<StreamInfo> streams = new List<StreamInfo>();

            string[] streamInfo = streamInfoString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string s in streamInfo) {
                string[] items = s.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                int width;
                int height;
                int bitrate;
                if (items.Length == 3 && Int32.TryParse(items[0], out width) && width > 0 &&
                    Int32.TryParse(items[1], out height) && height > 0 &&
                    Int32.TryParse(items[2], out bitrate) && bitrate > 0) {
                    StreamInfo si = new StreamInfo();
                    si.Size = new Size(width, height);
                    si.Bitrate = new ConstantBitrate(bitrate, false, TimeSpan.Zero);
                    streams.Add(si);
                }
            }

            return streams;
        }
    }
}
